const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const ZipPlugin = require('zip-webpack-plugin');
const UploadPlugin = require('./plugins/Upload-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const dayjs = require('dayjs');
console.log('NODE_ENV =', process.env.NODE_ENV);
//获取环境变量
const isProd = process.env.NODE_ENV == 'production';
//设置公共配置
const commonConfig = {
    publicPath: '', //isProd ? '/' : '', //全局统一资源路径
};
module.exports = {
    mode: process.env.NODE_ENV, //模式:development,production 写到命令行里面了
    entry: {
        index: './src/index.tsx', //入口文件
        about: './src/about.tsx',
    },
    output: {
        filename: isProd ? 'static/js/[name].[hash:8].js' : 'static/js/[name].js', //'bundle.[hash:8].js', //文件名
        path: path.resolve(__dirname, 'dist'), //导出目录，必须是绝对路径
        publicPath: commonConfig.publicPath, //全局统一资源路径
    },
    module: {
        noParse: /jquery/, //不要去解析该模块中的依赖库，它是独立的模块
        rules: [
            // {
            //     test: /\.htm$/,
            //     loader: 'html-loader',
            //     options: {
            //         esModule: false,
            //         // 除了img的src,还可以继续配置处理更多html引入的资源(不能在页面直接写路径,又需要webpack处理怎么办?先require再js写入).
            //         attributes: {
            //             list: [
            //                 // All default supported tags and attributes
            //                 '...',
            //                 {
            //                     tag: 'img',
            //                     attribute: 'data-src',
            //                     type: 'src',
            //                 },
            //                 {
            //                     tag: 'img',
            //                     attribute: 'data-srcset',
            //                     type: 'srcset',
            //                 },
            //             ],
            //         },
            //     },
            // },
            {
                test: /\.ejs$/,
                loader: 'ejs-loader',
                options: {
                    esModule: false,
                },
            },
            // {
            //     test: /\.(png|jpg|gif)$/,
            //     use: [
            //         {
            //             loader: 'file-loader',
            //             options: {
            //                 esModule: false,
            //             },
            //         },
            //     ],
            // },
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            esModule: false,
                            limit: 0 * 1024, //小于20kb转base64
                            outputPath: 'static/img',
                            name: isProd ? '[name].[hash:8].[ext]' : '[name].[ext]?[hash:8]',
                            // publicPath: '/cdn', //图片统一资源路径,outputPath失效，覆盖全局publicPath
                        },
                    },
                ],
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/i,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'static/css/fonts',
                        },
                    },
                ],
            },
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.s[ac]ss$/i,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: '../../', //针对css中图片地址转换错误问题
                        },
                    },
                    // 'style-loader',
                    'css-loader',
                    'postcss-loader',
                    'sass-loader',
                ], //sass-loader编译scss样式文件
            },
            {
                test: /\.tsx$/i,
                use: [
                    {
                        loader: 'ts-loader',
                    },
                ],
                exclude: /node_modules/,
            },
            {
                test: /\.js$/i,
                use: [
                    {
                        loader: 'eslint-loader',
                        options: {
                            formatter: require('eslint-friendly-formatter'),
                        },
                    },
                ],
                enforce: 'pre',
                exclude: /node_modules/,
            },
            {
                test: /\.js$/i,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        modules: false, // 默认值是auto,备选项： "amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false
                                        useBuiltIns: 'entry', //默认值是false,备选项： "usage" | "entry" | false
                                        //false：需要在 js 代码第一行主动 import '@babel/polyfill'，会将@babel/polyfill 整个包全部导入。
                                        // （不推荐，能覆盖到所有 API 的转译，但体积最大）
                                        // entry：需要在 js 代码第一行主动 import '@babel/polyfill'，会将 browserslist 环境不支持的所有垫片都导入。
                                        // （能够覆盖到'hello'.includes('h')这种句法，足够安全且代码体积不是特别大）
                                        // usage：项目里不用主动 import，会自动将代码里已使用到的、且 browserslist 环境不支持的垫片导入。
                                        // （但是检测不到'hello'.includes('h')这种句法，对这类原型链上的句法问题不会做转译，书写代码需注意）
                                        corejs: 3,
                                        // targets: [], //用来配置需要支持的的环境，不仅支持浏览器，还支持 node。如果没有配置 targets 选项，就会读取项目中的 browserslist 配置项。
                                        // loose: false //默认值是 false，如果 preset-env 中包含的 plugin 支持 loose 的设置，那么可以通过这个字段来做统一的设置。
                                    },
                                ],
                            ],
                            plugins: [
                                '@babel/plugin-transform-runtime', //减少babel中的helper重复问题
                            ],
                        },
                    },
                ],
                include: path.resolve(__dirname, 'src'), //包括
                exclude: /node_modules/, //排除node_modules目录
                // exclude: {
                //     and: [/node_modules/], // Exclude libraries in node_modules ...
                //     not: [
                //         // Except for a few of them that needs to be transpiled because they use modern syntax
                //         /unfetch/,
                //         /d3-array|d3-scale/,
                //         /@hapi[\\/]joi-date/,
                //     ],
                // },
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'src/views/index.html',
            title: 'My App',
            filename: 'index.html',
            meta: {},
            mode: isProd,
            minify: isProd,
            hash: !isProd, //文件后追加加hash值，不修改文件名
            chunks: ['index'], //指的是入口模块
            ...commonConfig,
        }),
        new HtmlWebpackPlugin({
            template: 'src/views/about.html',
            title: 'My About',
            filename: 'about.html',
            meta: {},
            minify: isProd,
            hash: !isProd, //文件后追加加hash值，不修改文件名
            chunks: ['about'], //指的是入口模块
            ...commonConfig,
        }),
        new MiniCssExtractPlugin({
            filename: isProd ? 'static/css/[name].[hash:8].css' : 'static/css/[name].css',
        }),
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, './build/vue-manifest.json'),
        }), //动态连接库中没有的文件才会被打包
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, './build/element_ui-manifest.json'),
        }), //动态连接库中没有的文件才会被打包
        // new webpack.ProvidePlugin({
        // 	$: 'jquery',
        // 	_: 'lodash',
        // }), //在每个模块注入
        new AddAssetHtmlPlugin({
            filepath: path.resolve(__dirname, './build/*.js'),
            outputPath: 'static/js',
            publicPath: 'static/js',
        }),
        new CopyPlugin([
            {
                from: 'public',
                to: 'static',
                ignore: ['libs/**/*'],
            },
        ]),
        new webpack.BannerPlugin('coding by leehoo'),
        new CleanWebpackPlugin(),
        new BundleAnalyzerPlugin({
            openAnalyzer: false,
            analyzerMode: 'static',
            reportFilename: 'report/index.html',
        }),
        new ZipPlugin({
            path: '../release',
            filename: 'dist.zip',
        }),
        new UploadPlugin({
            sourcePath: `./release/dist.zip`,
            targetPath: `/dist_${dayjs().format('YYYYMMDDhhmmss')}.zip`,
            config: {
                host: '192.168.252.72',
                port: 10021,
                user: 'fuser',
                password: 'tmkj@zgb123',
                keepalive: 10000,
            },
        }),
    ], //放着所有的webpack插件
    optimization: {
        minimizer: [
            new UglifyJsPlugin({
                // cache: true, //缓存
                // parallel: true, //并发,boollean,number
                // sourceMap: true,
            }),
            new OptimizeCssAssetsPlugin(),
        ],
        runtimeChunk: {
            name: 'manifest',
        }, //提取异步模块
        splitChunks: {
            chunks: 'initial', //起始位置，从入口开始(async:优化异步代码，initial:优化同步entry入口代码，all:优化同步和异步代码)
            minSize: 0, //生成新的chunk的最小体积，默认30KB（这个体积是压缩前的）
            minChunks: 2, //被entry引入的次数，默认1（为1时，适合分离node_modules里的第三方库）
            // automaticNameDelimiter: '~',// 定义文件名称连接符，默认~
            cacheGroups: {
                common: {
                    name: 'common',
                    test: /[\\/]src[\\/]/, //只打包src下的文件，node_modules下的三方库通过dllPlugin提前打包
                }, //自定义公共模块，符合该规则放入该模块，会覆盖掉默认的default
                // vendors: {
                //     name: 'vendor',
                //     priority: 1, //权重，多个分组冲突时，将代码放入权重高的里面
                //     test: /[\\/]node_modules[\\/]/,
                // }, //自定义抽离第三方组件，会覆盖webpack默认的，执行顺序为先走自定义分离模块=>默认的，如果不需要默认需要手动关闭
                vendors: false, //三方模块由dllPlugin提取，关闭webpack默认的三方库分离程序
            }, //缓存组
        }, //多入口分离出公共代码块
    }, //优化项
    resolve: {
        //     modules: [path.resolve('node_modules'), path.resolve('custom')], //限定包的查找范围
        alias: {
            vue: 'vue/dist/vue.js', //别名简写
        },
        //     mainFields: ['style', 'main'], //查找包中package.json的入口字段优先级，默认是main
        //     mainFiles: [], //入口文件的名字，默认是index.js
        //     extensions: ['.js', '.css', '.json'], //如果导入文件不写扩展名，如果存在同名不同扩展名，则按照该顺序查找
    }, //解析第三方包
    // externals: {
    //     jquery: '$', //import jquery but not build,方便全局引入，避免重复打包
    //     lodash: '_',
    //     vue: 'Vue',
    //     'vue-router': 'VueRouter',
    //     vuex: 'Vuex',
    //     axios: 'axios',
    //     'element-ui': 'ELEMENT',
    // },
    // devtool: 'eval-map', //增加映射文件，方便调试源代码；
    //默认，eval-map: 不产生文件，但是可以显示行和列，
    //source-map：产生单独文件，可以显示行和列，
    //cheap-module-source-map, 产生单独文件，不产生列
    //cheap-module-eval-source-map, 不产生文件，集成在打包后的文件中，不会产生列
    devServer: {
        // open: true, //自动打开浏览器
        //  openPage: '/different/page',//指定自动打开浏览器后打开的页面
        host: '0.0.0.0', //允许除本机外的其他机器访问
        useLocalIp: true, //此选项允许浏览器使用本地 IP 打开
        port: '12345', //端口号
        contentBase: path.join(__dirname, 'dist'), //指定服务器根目录
        // quiet: true, //除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
        stats: 'errors-only', //'none' | 'errors-only' | 'minimal' | 'normal' | 'verbose'
        // writeToDisk: true,//生成文件到硬盘，默认在内存
        // watchContentBase: true, //开启此选项后，在文件修改之后，会触发一次完整的页面重载。
        // publicPath: '/assets/',
        // https: true,//开启https
        // hot: true,//启用热更新
        // hotOnly: true,//只允许热更新，不允许页面刷新
        // index: 'index.html', //被作为索引文件的文件名
        // noInfo: true, //隐藏webpack bundle 信息之类的消息
        // clientLogLevel: 'none', //日志打印水平 'none' | 'info' | 'error' | 'warning'
        // compress: true,//gzip压缩
        // allowedHosts: ['host.com', 'subdomain.host.com', 'subdomain2.host.com', 'host2.com'], //此选项允许你添加白名单服务，允许一些开发服务器访问。
        // headers: {
        //     'X-Custom-Foo': 'bar',
        // },//给响应头中添加头信息
        // overlay: true, //当出现编译器错误或警告时，在浏览器中显示全屏覆盖层。默认禁用
        //代理方法01，主要用于跨域
        proxy: {
            '/api': {
                target: 'http://localhost', //代理到
                pathReWrite: {
                    '/api': '',
                }, //重写路径
                // secure: false, //接受运行在 HTTPS 上，且使用了无效证书的后端服务器
            },
        },
        //代理方法02，主要用模拟数据
        before: (app) => {
            app.get('/user', (req, res) => {
                res.json({
                    name: '123',
                });
            });
        },
        // after: app => {
        //     app.get('/user', (req, res) => {
        //         res.json({
        //             name: '123',
        //         });
        //     });
        // },
    },
    // watch: true, //修改代码，自动打包，主要针对npm run build
    // watchOptions: {
    //     poll: 1000, //毫秒，每秒询问一次
    //     aggregateTimeout: 500, //毫秒，防抖，我一直输入代码时，取消打包
    //     ignored: /node_modules/,
    // },
};
